﻿#include "StdAfx.h"
#include "UIFlash.h"
#include <atlcomcli.h>

#define DISPID_FLASHEVENT_FLASHCALL     ( 0x00C5 )
#define DISPID_FLASHEVENT_FSCOMMAND     ( 0x0096 )
#define DISPID_FLASHEVENT_ONPROGRESS    ( 0x07A6 )

namespace DuiLib
{
    IMPLEMENT_DUICONTROL(CFlashUI)

    CFlashUI::CFlashUI(void)
        : m_dwRef(0)
        , m_dwCookie(0)
        , m_pFlash(NULL)
        , m_pFlashEventHandler(NULL)
    {
        CDuiString strFlashCLSID=_T("{D27CDB6E-AE6D-11CF-96B8-444553540000}");
        OLECHAR szCLSID[100] = { 0 };
#ifndef _UNICODE
        ::MultiByteToWideChar(::GetACP(), 0, strFlashCLSID, -1, szCLSID, lengthof(szCLSID) - 1);
#else
        _tcsncpy(szCLSID, strFlashCLSID, lengthof(szCLSID) - 1);
#endif
        ::CLSIDFromString(szCLSID, &m_clsid);
    }

    CFlashUI::~CFlashUI(void)
    {
        if (m_pFlashEventHandler)
        {
            m_pFlashEventHandler->Release();
            m_pFlashEventHandler=NULL;
        }
        ReleaseControl();
    }

    LPCTSTR CFlashUI::GetClass() const
    {
        return DUI_CTR_FLASH;
    }

    LPVOID CFlashUI::GetInterface( LPCTSTR pstrName )
    {
        if( _tcsicmp(pstrName, DUI_CTR_FLASH) == 0 ) return static_cast<CFlashUI*>(this);
        return CActiveXUI::GetInterface(pstrName);
    }

    HRESULT STDMETHODCALLTYPE CFlashUI::GetTypeInfoCount( __RPC__out UINT *pctinfo )
    {
        return E_NOTIMPL;
    }

    HRESULT STDMETHODCALLTYPE CFlashUI::GetTypeInfo( UINT iTInfo, LCID lcid, __RPC__deref_out_opt ITypeInfo **ppTInfo )
    {
        return E_NOTIMPL;
    }

    HRESULT STDMETHODCALLTYPE CFlashUI::GetIDsOfNames( __RPC__in REFIID riid, __RPC__in_ecount_full(cNames ) LPOLESTR *rgszNames, UINT cNames, LCID lcid, __RPC__out_ecount_full(cNames) DISPID *rgDispId )
    {
        return E_NOTIMPL;
    }

    HRESULT STDMETHODCALLTYPE CFlashUI::Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr )
    {

        return S_OK;
        switch(dispIdMember)
        {
        case DISPID_FLASHEVENT_FLASHCALL:
            {
                if (pDispParams->cArgs != 1 || pDispParams->rgvarg[0].vt != VT_BSTR) 
                    return E_INVALIDARG;
                return this->FlashCall(pDispParams->rgvarg[0].bstrVal);
            }
        case DISPID_FLASHEVENT_FSCOMMAND:
            {
                if( pDispParams && pDispParams->cArgs == 2 )
                {
                    if( pDispParams->rgvarg[0].vt == VT_BSTR &&
                        pDispParams->rgvarg[1].vt == VT_BSTR )
                    {
                        return FSCommand(pDispParams->rgvarg[1].bstrVal, pDispParams->rgvarg[0].bstrVal);
                    }
                    else
                    {
                        return DISP_E_TYPEMISMATCH;
                    }
                }
                else
                {
                    return DISP_E_BADPARAMCOUNT;
                }
            }
        case DISPID_FLASHEVENT_ONPROGRESS:
            {
                return OnProgress(*pDispParams->rgvarg[0].plVal);
            }
        case DISPID_READYSTATECHANGE:
            {
                return this->OnReadyStateChange(pDispParams->rgvarg[0].lVal);
            }
        }

        return S_OK;
    }

    HRESULT STDMETHODCALLTYPE CFlashUI::QueryInterface( REFIID riid, void **ppvObject )
    {
        *ppvObject = NULL;

        if( riid == IID_IUnknown)
            *ppvObject = static_cast</*IOleWindow**/LPUNKNOWN>(this);
        else if( riid == IID_IDispatch)
            *ppvObject = static_cast<IDispatch*>(this);
        else if( riid ==  __uuidof(_IShockwaveFlashEvents))
            *ppvObject = static_cast<_IShockwaveFlashEvents*>(this);

        if( *ppvObject != NULL )
            AddRef();
        return *ppvObject == NULL ? E_NOINTERFACE : S_OK;
    }

    ULONG STDMETHODCALLTYPE CFlashUI::AddRef( void )
    {
        ::InterlockedIncrement(&m_dwRef); 
        return m_dwRef;
    }

    ULONG STDMETHODCALLTYPE CFlashUI::Release( void )
    {
        ::InterlockedDecrement(&m_dwRef);
        return m_dwRef;
    }

    HRESULT CFlashUI::OnReadyStateChange (long newState)
    {
        if (m_pFlashEventHandler)
        {
            return m_pFlashEventHandler->OnReadyStateChange(newState);
        }
        return S_OK;
    }

    HRESULT CFlashUI::OnProgress(long percentDone )
    {
        if (m_pFlashEventHandler)
        {
            return m_pFlashEventHandler->OnProgress(percentDone);
        }
        return S_OK;
    }

    HRESULT CFlashUI::FSCommand (_bstr_t command, _bstr_t args)
    {
        if (m_pFlashEventHandler)
        {
            return m_pFlashEventHandler->FSCommand(command,args);
        }
        return S_OK;
    }

    HRESULT CFlashUI::FlashCall( _bstr_t request )
    {
        if (m_pFlashEventHandler)
        {
            return m_pFlashEventHandler->FlashCall(request);
        }
        return S_OK;
    }

    void CFlashUI::ReleaseControl()
    {
        //GetManager()->RemoveTranslateAccelerator(this);
        RegisterEventHandler(FALSE);
        if (m_pFlash)
        {
            m_pFlash->Release();
            m_pFlash=NULL;
        }
    }

    bool CFlashUI::DoCreateControl()
    {
        if (!CActiveXUI::DoCreateControl())
            return false;
        //GetManager()->AddTranslateAccelerator(this);
        GetControl(__uuidof(IShockwaveFlash),(LPVOID*)&m_pFlash);
        RegisterEventHandler(TRUE);
        return true;
    }

    void CFlashUI::SetFlashEventHandler( CFlashEventHandler* pHandler )
    {
        if (m_pFlashEventHandler!=NULL)
        {
            m_pFlashEventHandler->Release();
        }
        if (pHandler==NULL)
        {
            m_pFlashEventHandler=pHandler;
            return;
        }
        m_pFlashEventHandler=pHandler;
        m_pFlashEventHandler->AddRef();
    }

    LRESULT CFlashUI::TranslateAccelerator( MSG *pMsg )
    {
        if(pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST)
            return S_FALSE;

        if( m_pFlash == NULL )
            return E_NOTIMPL;

        // 当前Web窗口不是焦点,不处理加速键
        BOOL bIsChild = FALSE;
        HWND hTempWnd = NULL;
        HWND hWndFocus = ::GetFocus();

        hTempWnd = hWndFocus;
        while(hTempWnd != NULL)
        {
            if(hTempWnd == m_hwndHost)
            {
                bIsChild = TRUE;
                break;
            }
            hTempWnd = ::GetParent(hTempWnd);
        }
        if(!bIsChild)
            return S_FALSE;

        CComPtr<IOleInPlaceActiveObject> pObj;
        if (FAILED(m_pFlash->QueryInterface(IID_IOleInPlaceActiveObject, (LPVOID *)&pObj)))
            return S_FALSE;

        HRESULT hResult = pObj->TranslateAccelerator(pMsg);
        return hResult;
    }

    HRESULT CFlashUI::RegisterEventHandler( BOOL inAdvise )
    {
        if (m_pFlash==NULL)
            return S_FALSE;

        HRESULT hr=S_FALSE;
        CComPtr<IConnectionPointContainer>  pCPC;
        CComPtr<IConnectionPoint> pCP;

        hr=m_pFlash->QueryInterface(IID_IConnectionPointContainer,(void **)&pCPC);
        if (FAILED(hr))
            return hr;
        hr=pCPC->FindConnectionPoint(__uuidof(_IShockwaveFlashEvents),&pCP);
        if (FAILED(hr))
            return hr;

        if (inAdvise)
        {
            hr = pCP->Advise((IDispatch*)this, &m_dwCookie);
        }
        else
        {
            hr = pCP->Unadvise(m_dwCookie);
        }
        return hr; 
    }

};